package com.billdimmick.merkabah;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class BasicSQSSecurityAdapter extends SQSSecurityAdapter {

	private static final Log log=LogFactory.getLog(BasicSQSSecurityAdapter.class);
	
	private static final String DEFAULT_KEYPAIR_ALGORITHM = "RSA";
	private static final Map<String, Integer> DEFAULT_ALGORITHM_STRENGTHS;
	
	static {
		Map<String, Integer> strengths=new HashMap<String, Integer>();
		strengths.put(DEFAULT_KEYPAIR_ALGORITHM, 1024);
		strengths.put("DSA", 1024);
		DEFAULT_ALGORITHM_STRENGTHS=Collections.unmodifiableMap(strengths);
	}
	
	
	private final String awsAccessId;
	private final String awsSecretKey;
	private final Map<String, PrivateKey> privatekeys=new HashMap<String, PrivateKey>();
	private final Map<String, PublicKey> publickeys=new HashMap<String, PublicKey>();
	private final Map<String, Certificate> certificates=new HashMap<String, Certificate>();

	
	public BasicSQSSecurityAdapter(final String awsAccessId, final String awsSecretKey) {
		Validate.notEmpty(awsAccessId, "Parameter 'awsAccessId' may not be null or blank.");
		Validate.notEmpty(awsSecretKey, "Parameter 'awsSecretKey' may not be null or blank.");
		this.awsAccessId=awsAccessId;
		this.awsSecretKey=awsSecretKey;
	}

	public BasicSQSSecurityAdapter(final Properties properties) {
		Validate.notNull(properties, "Provided properties cannot be null.");
		this.awsAccessId=properties.getProperty("AWSAccessId");
		this.awsSecretKey=properties.getProperty("AWSSecretKey");
		Validate.notEmpty(this.awsAccessId, "Property 'AWSAccessId' may not be null or blank.");
		Validate.notEmpty(this.awsSecretKey, "Property 'AWSSecretKey' may not be null or blank.");
	}
	
	public String getAWSAccessId() {
		return this.awsAccessId;
	}

	public String getAWSSecretKey() {
		return this.awsSecretKey;
	}
	
	public void addCertificate(final String name, final Certificate certificate) {
		Validate.notNull(name, "Provided name cannot be null.");
		Validate.notNull(certificate, "Provided certificate cannot be null.");
		certificates.put(name, certificate);
	}

	public void addPublicKey(final String name, final PublicKey key) {
		Validate.notNull(name, "Provided name cannot be null.");
		Validate.notNull(key, "Provided key cannot be null.");
		publickeys.put(name, key);
	}

	public void addPrivateKey(final String name, final PrivateKey key) {
		Validate.notNull(name, "Provided name cannot be null.");
		Validate.notNull(key, "Provided key cannot be null.");
		privatekeys.put(name, key);
	}
	
	public void generateKeypair(final String name) {
		try {
			generateKeypair(name, DEFAULT_KEYPAIR_ALGORITHM);
		} catch (NoSuchAlgorithmException nsae) {
			throw new IllegalStateException(String.format("Does your Java installation support '%s'?", DEFAULT_KEYPAIR_ALGORITHM), nsae);
		}
	}

	public void generateKeypair(final String name, final String algorithm) throws NoSuchAlgorithmException
	{
		Validate.isTrue(DEFAULT_ALGORITHM_STRENGTHS.containsKey(algorithm), "Default algorithm strength not found.");
		generateKeypair(name, algorithm, DEFAULT_ALGORITHM_STRENGTHS.get(algorithm));
	}
	
	public void generateKeypair(final String name, final String algorithm, final int strength) throws NoSuchAlgorithmException {
		Validate.notNull(name, "Provided name cannot be null.");
		Validate.notNull(algorithm, "Provided name cannot be null.");
		Validate.isTrue(strength>0, "Provided strength must be positive.");
		KeyPairGenerator generator=KeyPairGenerator.getInstance(algorithm);
		generator.initialize(strength);
		KeyPair pair=generator.generateKeyPair();
		addPrivateKey(name, pair.getPrivate());
		addPublicKey(name, pair.getPublic());
	}
	
	@Override
	protected Certificate getCertificate(final String name) {
		return certificates.get(name);
	}
	
	@Override
	protected PrivateKey getPrivateKey(final String name) {
		return privatekeys.get(name);
	}
	
	@Override
	protected PublicKey getPublicKey(final String name) {
		return publickeys.get(name);
	}
	
	public void evict() {
		publickeys.clear();
		privatekeys.clear();
		certificates.clear();
	}
}
